﻿using Cache;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Util;

namespace API.Filters
{
    /// <summary>
    /// 缓存过滤器，设置接口缓存
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class CacheAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// 是否清除缓存
        /// </summary>
        public bool Clear { get; set; } = false;

        /// <summary>
        /// 缓存时间，默认一年
        /// </summary>
        public int Timeout = (int)EnumCacheTime.Global;

        private string guid = "";

        /// <summary>
        /// 执行前
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //请求
            var request = context.HttpContext.Request;
            string control = context.RouteData.Values["Controller"].ToString();
            string aciton = context.RouteData.Values["Action"].ToString();

            //Preflighted Requests(预检请求)处理
            if (request.Headers.ContainsKey("Origin") && request.Method.ToUpper() == "OPTIONS")
            {
                context.Result = new OkResult();
                return;
            }
            string content = "";
            //请求内容
            if (!context.ActionDescriptor.Properties.ContainsKey("RequestBody"))
            {
                using (var sr = new StreamReader(request.Body))
                {
                    content = sr.ReadToEnd();
                    if (string.IsNullOrEmpty(content) && (request.Method.ToUpper() == "POST" || request.Method.ToUpper() == "PUT" || request.Method.ToUpper() == "GET" || request.Method.ToUpper() == "DELETE") && context.ActionArguments.Count > 0)
                        content = context.ActionArguments.FirstOrDefault().Value.ToJson();
                    context.ActionDescriptor.Properties["RequestBody"] = content;
                }
            }
            else
                content = context.ActionDescriptor.Properties["RequestBody"].ToString();
            if (!Clear)
            {
                int code = content.GetHashCode();
                string result = GlobalData.Cache.Get(string.Format(RedisKey.BusinessActionKey, control, aciton, code));
                if (!string.IsNullOrWhiteSpace(result))
                {
                    guid = Guid.NewGuid().ToString();
                    context.ActionDescriptor.Properties[$"IsCached_{control}_{aciton}_{code}_{guid}"] = 1;
                    context.Result = new ObjectResult(result);
                    return;
                }
            }

            base.OnActionExecuting(context);
        }

        /// <summary>
        /// 执行前
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
        }

        /// <summary>
        /// 执行前
        /// </summary>
        /// <param name="context"></param>
        public override void OnResultExecuting(ResultExecutingContext context)
        {
            base.OnResultExecuting(context);
        }

        /// <summary>
        /// 执行后
        /// </summary>
        /// <param name="context"></param>
        public override void OnResultExecuted(ResultExecutedContext context)
        {
            var req = context.HttpContext.Request;
            string control = context.RouteData.Values["Controller"].ToString();
            string aciton = context.RouteData.Values["Action"].ToString();
            var properties = context.ActionDescriptor.Properties;
            string query = !properties.ContainsKey("RequestBody") ? "" : context.ActionDescriptor.Properties["RequestBody"].ToString();
            int code = query.GetHashCode();
            string iscache = !properties.ContainsKey($"IsCached_{control}_{aciton}_{code}_{guid}") ? "" : context.ActionDescriptor.Properties[$"IsCached_{control}_{aciton}_{code}_{guid}"].ToString();
            string result = "";
            if (context.Result != null && string.IsNullOrWhiteSpace(iscache))
            {
                result = ((ObjectResult)context.Result).Value.ToJson();
                GlobalData.Cache.Set(string.Format(RedisKey.BusinessActionKey, control, aciton, query.GetHashCode()), result, Timeout);
                GlobalData.Cache.SAdd(string.Format(RedisKey.BusinessControlKey, control), string.Format(RedisKey.BusinessActionKey, control, aciton, query.GetHashCode()));
                GlobalData.Cache.SAdd(RedisKey.BusinessKey, string.Format(RedisKey.BusinessControlKey, control));
            }
            if (Clear)
            {
                List<string> members = new List<string>();
                foreach (var member in GlobalData.Cache.SMembers(string.Format(RedisKey.BusinessControlKey, control)))
                {
                    GlobalData.Cache.Remove(member);
                    members.Add(member);
                }
                GlobalData.Cache.SRem(string.Format(RedisKey.BusinessControlKey, control), members.ToArray());
            }

            base.OnResultExecuted(context);
        }
    }
}
